<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    

<script>

// 全局变量的生命周期：进入页面时创建，关闭页面时销毁
// var a = 1 // 全局变量
// function fn1(){
//     a++
//     console.log( a )
// }
// fn1()// 2
// fn1()// 3
// fn1()// 4
// 问题：全局变量容易造成命名污染，容易被覆盖，占用更多内存


// 局部变量的生命周期：函数调用时创建，函数执行完成后销毁
// function fn2(){
//     var a = 1 // 局部变量
//     a++
//     console.log( a ) 
// }
// fn2()// 2
// fn2()// 2
// fn2()// 2
// 问题：每次函数执行完成，局部变量都被销毁，导致a的值没有被保存下来


// 闭包
// 闭包分为两种：无效闭包和有效闭包

// 无效闭包：
    // 函数嵌套，内部函数使用了外部函数的变量/参数
// function outer(){// 外部函数
//     var a = 1 // 局部变量
//     function inner(){// 内部函数
//         a++
//         console.log( a )// 使用了外部函数的变量/参数
//     }
//     inner()
// }
// outer()// 2 执行完成后，a还是被销毁
// outer()// 2 执行完成后，a还是被销毁
// outer()// 2 执行完成后，a还是被销毁


// 有效闭包：
    // 函数嵌套，内部函数使用了外部函数的变量/参数
    // 在函数外部保持对内部函数的引用
    // 在外部调用内部函数
function outer(){// 外部函数
    var a = 1 // 局部变量
    function inner(){// 内部函数
        a++
        console.log( a )// 使用了外部函数的变量/参数
    }
    return inner // 返回内部函数
}
var inner = outer() // 在函数外部保持对内部函数的引用
// outer()执行完成后，a并没有被销毁
// 因为inner函数一值在使用a，然后全局的inner又在引用内部的inner
inner() // 2 在外部调用内部函数
inner() // 3 在外部调用内部函数
inner() // 4 在外部调用内部函数

// 闭包的应用场景：
// 1.在函数外部操作函数内部的局部变量（上面的示例）

// 2.模块化中使用闭包
var module1 = (function (){// 模块
    // 局部作用域1
    var a = 1
    var say = function (){
        console.log( 'hi 1',a )
    }
    return {a,say}
})()
module1.say()

var module2 = (function (){// 模块
    // 局部作用域2
    var a = 2
    var say = function (){
        console.log( 'hi 2',a )
    }
    return {a,say}
})()
module2.say()

// 3.函数防抖
function debounce(fn,time){
    let timer
    return function (){// debounceJsonp
        clearTimeout(timer)
        timer = setTimeout(function (){
            fn()// 对fn进行防抖处理
        },time)
    }
}
let debounceJsonp = debounce(jsonp,300)// 防抖处理

// 4.函数节流
function throttle(fn,time){
    let timer // 记录计时器id
    let lastTime // 记录上次触发时间
    return function (x){// throttleTest
        let nowTime = Date.now()// 记录事件当前触发的时间
        // 需求：每隔time毫秒执行一次
        if (lastTime && nowTime < lastTime+time) {
            // 上次触发和当前触发间隔还没到time毫秒
            clearTimeout(timer)
            timer = setTimeout(function (){
                lastTime = nowTime// 更新上次触发时间
                fn(x)
            },time)
        }
        else{
            lastTime = nowTime// 更新上次触发时间
            fn(x)// 立即执行函数
        }
    }
}
let throttleTest = throttle(test,400)// 节流处理

</script>
</body>
</html>